/**************************************************
 * Filename: ConnectionFactory.java
 * Version: v1.0
 * CreatedDate: 2011-5-5
 * Copyright (C) 2011 By cafebabe.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see http://www.gnu.org/licenses/.
 *
 * If you would like to negotiate alternate licensing terms, you may do
 * so by contacting the author: talentyao@foxmail.com
 ***************************************************/

package com.ywh.dbpools;

import java.sql.SQLException;
import java.util.Hashtable;
import java.util.Vector;

import javax.naming.NameAlreadyBoundException;
import javax.naming.NameNotFoundException;
import javax.sql.DataSource;

/**
 * 连接池类厂，该类常用来保存多个数据源名称和数据库连接池对应的哈希
 * 
 * @author cafebabe
 * @since 2011-5-5
 * @version 1.0
 */
public class ConnectionFactory {
	private static String DS_FILENAME = "conf/datasource_config.xml";
	// 该哈希表用来保存数据源名和连接池对象的关系表
	static Hashtable<String, DataSource> connectionPools = null;
	static {
		connectionPools = new Hashtable<String, DataSource>(2, 0.75F);
		init();
	}

	/**
	 * 从连接池工厂中获取指定名称对应的连接池对象
	 * 
	 * @param dataSource
	 *            连接池对象对应的名称
	 * @return DataSource 返回名称对应的连接池对象
	 * @throws NameNotFoundException
	 *             无法找到指定的连接池
	 */
	public static DataSource lookup(String dataSource)
			throws NameNotFoundException {
		DataSource ds = connectionPools.get(dataSource);
		if (ds == null) {
			throw new NameNotFoundException(dataSource);
		}
		return ds;
	}

	/**
	 * 将指定的名字和数据库连接配置绑定在一起并初始化数据库连接池
	 * 
	 * @param name
	 *            对应连接池的名称
	 * @param param
	 *            连接池的配置参数，具体请见类ConnectionParam
	 * @return DataSource 如果绑定成功后返回连接池对象
	 * @throws NameAlreadyBoundException
	 *             一定名字name已经绑定则抛出该异常
	 * @throws ClassNotFoundException
	 *             无法找到连接池的配置中的驱动程序类
	 * @throws IllegalAccessException
	 *             连接池配置中的驱动程序类有误
	 * @throws InstantiationException
	 *             无法实例化驱动程序类
	 * @throws SQLException
	 *             无法正常连接指定的数据库
	 */
	public static DataSource bind(String name, ConnectionParameter param)
			throws NameAlreadyBoundException, ClassNotFoundException,
			IllegalAccessException, InstantiationException, SQLException {
		DataSource source = null;
		try {
			lookup(name);
			throw new NameAlreadyBoundException(name);
		} catch (NameNotFoundException e) {
			source = new DataSourceImpl(param);
			// source.initConnection();
			connectionPools.put(name, source);
		}
		return source;
	}

	/**
	 * 重新绑定数据库连接池
	 * 
	 * @param name
	 *            对应连接池的名称
	 * @param param
	 *            连接池的配置参数，具体请见类ConnectionParam
	 * @return DataSource 如果绑定成功后返回连接池对象
	 * @throws NameAlreadyBoundException
	 *             一定名字name已经绑定则抛出该异常
	 * @throws ClassNotFoundException
	 *             无法找到连接池的配置中的驱动程序类
	 * @throws IllegalAccessException
	 *             连接池配置中的驱动程序类有误
	 * @throws InstantiationException
	 *             无法实例化驱动程序类
	 * @throws SQLException
	 *             无法正常连接指定的数据库
	 */
	public static DataSource rebind(String name, ConnectionParameter param)
			throws NameAlreadyBoundException, ClassNotFoundException,
			IllegalAccessException, InstantiationException, SQLException {
		try {
			unbind(name);
		} catch (Exception e) {
		}
		return bind(name, param);
	}

	/**
	 * 删除一个数据库连接池对象
	 * 
	 * @param name
	 * @throws NameNotFoundException
	 */
	public static void unbind(String name) throws NameNotFoundException {
		DataSource dataSource = lookup(name);
		if (dataSource instanceof DataSourceImpl) {
			DataSourceImpl dsi = (DataSourceImpl) dataSource;
			try {
				dsi.close();
			} catch (Exception e) {
			} finally {
				dsi = null;
			}
		}
		connectionPools.remove(name);
	}

	/**
	 * 从配置文件加载数据源
	 * 
	 * @param props
	 */
	private static void init() {
		DataSourceParser pd = new DataSourceParser();
		System.out.println("Reading connection parameter from " + DS_FILENAME);
		// 读取数据库配置文件
		Vector<ConnectionParameter> drivers = pd.readConfigInfo(DS_FILENAME);
		System.out.println("Reading complete！");
		for (ConnectionParameter cp : drivers) {
			try {
				System.out.println("Binding data source:" + cp.getName()
						+ "......");
				bind(cp.getName(), cp);
				System.out.println("Bind successfully!!!");
			} catch (Exception e) {
				System.err.println("Initial connection pool from "
						+ DS_FILENAME + " failed!");
				e.printStackTrace();
			}
		}

	}

	// public static void main(String[] args) throws Exception{
	// DataSource ds = lookup("sms");
	// ds.getConnection();
	// }
}
